/*
 *
 *  *    Copyright 2020-2021 Luter.me
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *      http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

package com.luter.heimdall.plugins.scheduler.authorization;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.luter.heimdall.core.authorization.store.AuthorizationStore;
import com.luter.heimdall.core.config.ConfigManager;
import com.luter.heimdall.core.config.HeimdallProperties;
import org.slf4j.Logger;

import java.time.Duration;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

import static org.slf4j.LoggerFactory.getLogger;

/**
 * 权限缓存清理任务 默认实现
 * <p>
 * <p>
 * 定期清理缓存中无效的用户权限和应用权限缓存
 * <p>
 * 注意:只针对内存缓存(isSelfExpired)有效，外部缓存，比如:redis，有自动过期机制
 *
 * @author luter
 */
public class DefaultAuthorizationValidatingScheduler implements AuthorizationValidatingScheduler {
    /**
     * The constant log.
     */
    private static final transient Logger log = getLogger(DefaultAuthorizationValidatingScheduler.class);

    /**
     * 初始化权限缓存定时清理程序
     *
     * @param authorizationStore 权限 AuthorizationStore Store
     */
    public DefaultAuthorizationValidatingScheduler(AuthorizationStore authorizationStore) {
        HeimdallProperties config = ConfigManager.getConfig();
        this.startTask(authorizationStore, config.getScheduler().isAuthorityEnabled(),
                config.getScheduler().getInitialDelay(), config.getScheduler().getTokenPeriod());
    }

    /**
     * 开启任务
     *
     * @param authorizationStore 权限 AuthorizationStore Store
     * @param enabled            是否开启任务
     * @param initialDelay       初始延迟。程序启动后延迟多少秒开始执行任务。单位:秒。
     * @param period             每隔多少秒执行一次。单位：秒
     */
    public void startTask(AuthorizationStore authorizationStore, boolean enabled, long initialDelay, long period) {
        if (enabled) {
            log.info("[DefaultAuthorizationValidatingScheduler]:: enabled = [true], initialDelay = [{}], period = [{}]",
                    initialDelay, period);
        } else {
            log.warn("[DefaultAuthorizationValidatingScheduler]:: enabled = [false], initialDelay = [{}], period = [{}]",
                    initialDelay, period);
        }
        if (enabled && null != authorizationStore) {
            Runnable runnable = () -> {
                //内存缓存
                if (!authorizationStore.isSelfExpired()) {
                    try {
                        log.info("[DefaultAuthorizationValidatingScheduler]::Invoke the  authorization validating schedule task now.");
                        //执行清理任务
                        log.warn("执行内存权限清理任务");
                        authorizationStore.removeAllUserAuthorities();
                        authorizationStore.removeAllAppAuthorities();

                    } catch (Exception e) {
                        log.error("[DefaultAuthorizationValidatingScheduler]::error happened while execute authorization " +
                                "validating task :{}", e.getMessage());
                    }
                }

            };
            //延迟执行时间（秒），最小 1 小时
            initialDelay = Math.max(initialDelay, Duration.ofHours(1).getSeconds());
            //执行的时间间隔（秒），最小 12 小时
            period = Math.max(period, Duration.ofHours(12).getSeconds());
            log.info("[DefaultAuthorizationValidatingScheduler]::Authorization validating task is enabled," +
                    "initialDelay:[ {} ],period:[ {} ]", initialDelay, period);
            ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("-thread-%d").setDaemon(true).build();
            ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1, namedThreadFactory);
            executorService.scheduleWithFixedDelay(runnable, initialDelay, period, TimeUnit.SECONDS);
        } else {
            log.warn("[DefaultAuthorizationValidatingScheduler]::Authorization validating task is disabled");
        }

    }
}
